#include "collectionbox.h"

ATOM CollectionBox::_wndClass = NULL;

CollectionBox::CollectionBox()
{
	_collection = NULL;
	_hWnd = NULL;
}

CollectionBox::~CollectionBox()
{
	if( IsWindow( _hWnd ) )
	{
		//Detach the instance from this window and destroy the window.
		SetWindowLongPtr( _hWnd, GWLP_USERDATA, NULL );
		DestroyWindow( _hWnd );
	}
}

BOOL CollectionBox::setPosition( RECT rect, BOOL repaint )
{
	return MoveWindow(
		_hWnd,
		rect.left,
		rect.top,
		rect.right - rect.left,
		rect.bottom - rect.top,
		repaint
		);
}

void CollectionBox::show( int nCmdShow )
{
	ShowWindow( _hWnd, nCmdShow );
}

Collection* CollectionBox::collection() const
{
	return _collection;
}

void CollectionBox::setCollection( Collection *collection )
{
	_collection = collection;

	//Repaint the window.
	InvalidateRect( _hWnd, NULL, TRUE );
}

bool CollectionBox::create( HWND hWndParent, HINSTANCE hInstance )
{
	if( registerWndClass( hInstance ) == false )
	{
		return false;
	}

	_hWnd = CreateWindowEx(
		WS_EX_CLIENTEDGE, //dwExStyle
		(LPCWSTR) _wndClass, //lpClassName
		L"", //lpWindowName
		WS_CHILD, //dwStyle
		CW_USEDEFAULT, //X
		CW_USEDEFAULT, //Y
		200, //nWidth
		150, //nHeight
		hWndParent, //hWndParent
		NULL, //hMenu
		hInstance, //hInstance
		NULL //lpParam
		);
	if( _hWnd == NULL )
	{
		return false;
	}

	//Store a pointer to this CollectionBox instance with the window.
	SetWindowLongPtr( _hWnd, GWLP_USERDATA, (LONG_PTR) this );
	UpdateWindow( _hWnd );
	return true;
}

LRESULT CollectionBox::handleMessage( UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	switch( uMsg )
	{
	case WM_LBUTTONDOWN:
		{
			//If the user clicks a thumbnail, select the thumbnail and return zero.
			POINT posMouse, posThumbnail;
			posMouse.x = LOWORD( lParam );
			posMouse.y = HIWORD( lParam );

			//Eliminate offset on the top and left of all images.
			posMouse.x -= 20;
			posMouse.y -= 10;

			posThumbnail.x = posMouse.x / 160;
			posThumbnail.y = posMouse.y / 160;

			if( posMouse.x % 160 < 120 &&
				posMouse.y % 160 < 100 &&
				posMouse.x > 0 &&
				posMouse.y > 0 )
			{
				RECT clientRect;
				GetClientRect( _hWnd, &clientRect );
				unsigned int cxImages = ( clientRect.right - clientRect.left ) / 160;
				if( cxImages == 0 )
					cxImages = 1;

				unsigned int numImage = posThumbnail.y * cxImages + posThumbnail.x;
				if( numImage < _collection->size() )
				{
					//The user clicked a thumbnail.
					_collection->setSelected( numImage );
					InvalidateRect( _hWnd, NULL, FALSE );
					return 0;
				}
			}
			//Clear selection.
			_collection->setSelected( -1 );

			//Repaint the window.
			InvalidateRect( _hWnd, NULL, FALSE );
		}
		break;
	case WM_PAINT:
		{
			PAINTSTRUCT ps;
			HDC hDC = BeginPaint( _hWnd, &ps );

			if( _collection )
			{
				//Calculate the number of images which fit in one row on the screen.
				//A thumbnail is 120 pixels wide and has 20 pixels padding on both sides.
				RECT clientRect;
				GetClientRect( _hWnd, &clientRect );
				unsigned int cxImages = ( clientRect.right - clientRect.left ) / 160;
				if( cxImages == 0 )
					cxImages = 1;

				for( unsigned int i = 0; i < _collection->size(); ++i )
				{
					//Create a brush to draw the rectangle for the thumbnail.
					COLORREF brushColor = ( (int) i == _collection->selected() )?
						RGB(   0,   0, 128 ) :
						RGB( 255, 255, 255 );
					HBRUSH hBrush = CreateSolidBrush( brushColor );

					//Select the brush to use.
					SelectObject( hDC, hBrush );

					POINT pos; //Topleft position of the thumbnail
					pos.x = 160 * ( i % cxImages ) + 20;
					pos.y = 160 * ( i / cxImages ) + 10;
					Rectangle(
						hDC, //hDC
						pos.x - 1, //left
						pos.y - 1, //top
						pos.x + 121, //right
						pos.y + 101 //bottom
						);

					//We don't need the brush anymore.
					DeleteObject( hBrush );

					CollectionImage &img = _collection->getImage( i );
					Ref<DIB> thumbnail = img.thumbnail();
					SIZE size = thumbnail->size();
					SetDIBitsToDevice(
						hDC, //hDC
						pos.x + ( 120 - size.cx ) / 2, //xDest
						pos.y + ( 100 - size.cy ) / 2, //yDest
						size.cx, //w
						size.cy, //h
						0, //xSrc
						0, //ySrc
						0, //StartScan
						size.cy, //cLines
						thumbnail->data(), //lpvBits
						&*thumbnail->format(), //lpbmi
						DIB_RGB_COLORS //ColorUse
						);

					wchar_t *fileName, *cur = img.fileName();
					while( cur )
					{
						fileName = cur;
						if( cur = wcschr( cur, L'\\' ) )
							++cur;
					}

					//Traw the the text (filename).
					TextOut( hDC, pos.x, pos.y + 110, fileName, wcslen( fileName ) );
				}
			}

			EndPaint( _hWnd, &ps );
		}
		break;
	default:
		break;
	}
	//Call the default message handler for this window.
	return DefWindowProc( _hWnd, uMsg, wParam, lParam );
}

HWND CollectionBox::hWnd() const
{
	return _hWnd;
}

bool CollectionBox::registerWndClass( HINSTANCE hInstance )
{
	if( _wndClass == NULL )
	{
		WNDCLASSEX wc;

		wc.cbSize        = sizeof( WNDCLASSEX );
		wc.style         = 0;
		wc.lpfnWndProc   = &Window::ooDispatcher;
		wc.cbClsExtra    = 0;
		wc.cbWndExtra    = 0;
		wc.hInstance     = hInstance;
		wc.hIcon         = LoadIcon( NULL, IDI_APPLICATION );
		wc.hCursor       = LoadCursor( NULL, IDC_ARROW );
		wc.hbrBackground = (HBRUSH) ( COLOR_WINDOW + 1 );
		wc.lpszMenuName  = NULL;
		wc.lpszClassName = L"CollectionBox";
		wc.hIconSm       = LoadIcon( NULL, IDI_APPLICATION );

		_wndClass = RegisterClassEx( &wc );
		if( _wndClass == NULL )
		{
			//Registration of window class failed.
			return false;
		}
	}
	return true;
}
